#include <sstream>
#include <cctype>
#include <utility>
#include <Windows.h>
#include "HttpRequestPack.h"
#include "StringHelper.h"

#define HTTP_CONNECT_DEFAULT_PORT 0x1bb
#define HTTP_DEFAULT_PORT 80

using namespace std;
using namespace log4cplus;

Logger HttpRequestPack::log=GetLogger(LOG4CPLUS_TEXT("HttpRequestPack"));

HttpRequestPack::~HttpRequestPack()
{
	if(m_Body!=NULL)
	{
		delete []m_Body;
	}
	if(m_tempBuffer!=NULL)
	{
		FreeTempBuffer();
	}
}

void HttpRequestPack::AppendData(char *first,char *last)
{
	m_tempBuffer->append(first,last);
}

bool HttpRequestPack::IsValid()
{
	if(m_tempBuffer->find("\r\n\r\n")==string::npos)
	{
		return false;
	}
	if(!m_headerParsed)
	{
		ParseHeader();
	}
	map<string,string>::iterator iter=m_headers.find("Content-Length");
	if(iter!=m_headers.end())
	{
		unsigned long size = atol(iter->second.c_str());
		if(BodySize()>=size)
		{
			if(log.isEnabledFor(DEBUG_LOG_LEVEL))
			{
				LogDiffCodeMsg(log,LOG4CPLUS_TEXT("Http request header:\r\n%s"),*m_tempBuffer);
			}
			CopyBody();
			FreeTempBuffer();
			return true;
		}
		return false;
	}
	else
	{
		if(log.isEnabledFor(DEBUG_LOG_LEVEL))
		{
			LogDiffCodeMsg(log,LOG4CPLUS_TEXT("Http request header:\r\n%s"),*m_tempBuffer);
		}
		FreeTempBuffer();
		return true;
	}
}

void HttpRequestPack::InitializeRequestRange(long long &min,long long &max)
{
	map<string,string>::iterator iter=m_headers.find("Range");
	if(m_Type!="CONNECT")
	{
		if(iter!=m_headers.end())
		{
			string::size_type index=iter->second.find("-");
			istringstream is(iter->second.substr(7,index-7));
			is>>min;
			if(index<iter->second.size()-1)
			{
				is.seekg(0,ios::beg);
				is.rdbuf()->str(iter->second.substr(index+1));
				is>>max;
			}
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("Initialize request file size,min:%d,max:%d."),min,max);
		}
		else
		{
			min=0;
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("Initialize request file size,min:%d."),min);
		}
	}
}

void HttpRequestPack::ParseHeader()
{
	istringstream is(*m_tempBuffer);
	string temp;

	getline(is,temp);
	temp.erase(temp.end()-1);
	string::size_type spaceStartIndex = StringHelper::ReadToSpaceA(temp,0,m_Type);
	string::size_type spaceRStartIndex = StringHelper::ReverseReadToSpaceA(temp,string::npos,m_Version);
	m_Path=temp.substr(spaceStartIndex+1,spaceRStartIndex-spaceStartIndex-1);
	m_fullRequestUrl=m_Path;

	while(getline(is,temp)&&temp!="\r")
	{
		string::size_type index=temp.find(":");
		m_headers.insert(make_pair(temp.substr(0,index),temp.substr(index+1,temp.size()-2-index)));
	}
	m_BodyIndex=is.tellg();
	ParseHostAndPath();
	m_headerParsed=true;
}

void HttpRequestPack::ParseHostAndPath()
{
	string temp(m_Type);
	StringHelper::ToUpperA(temp);
	if(temp=="CONNECT")
	{
		string::size_type index=m_Path.find(":");
		if(index!=string::npos)
		{
			m_ServerName=m_Path.substr(0,index);
			m_serverPort=static_cast<unsigned short>(atoi(m_Path.substr(index+1).c_str()));
		}
		else
		{
			m_ServerName=m_Path;
			m_serverPort=HTTP_CONNECT_DEFAULT_PORT;
		}
		m_Path="";
	}
	else
	{
		string host=m_headers.find("Host")->second;
		string::size_type index=host.find(":");
		if(index!=string::npos)
		{
			m_ServerName=host.substr(1,index-1);
			m_serverPort=static_cast<unsigned short>(atoi(host.substr(index+1).c_str()));
		}
		else
		{
			m_ServerName=host.substr(1);
			m_serverPort=HTTP_DEFAULT_PORT;
		}
		index=m_Path.find("/",7);
		if(index==string::npos)
		{
			m_Path="";
		}
		else
		{
			m_Path=m_Path.substr(index);
		}
	}
}

void HttpRequestPack::SetTempBuffer(string *bufValue)
{
	m_tempBuffer=bufValue;
}

void HttpRequestPack::FreeTempBuffer()
{
	delete m_tempBuffer;
	m_tempBuffer=NULL;
}

string::size_type HttpRequestPack::BodySize()
{
	return m_tempBuffer->size()-m_BodyIndex;
}

void HttpRequestPack::CopyBody()
{
	string::size_type size=BodySize();
	if(size>0)
	{
		m_Body=new char[size];
		memcpy_s(m_Body,size,m_tempBuffer->c_str()+m_BodyIndex,size);
	}
}